/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package methods;

import core.Constants;

/**
 *
 * @author Alexey Chirkov
 */
public class NeYavnaya implements Method {

    private static NeYavnaya obj = null;
    private int K = 4;
    private int I = 4;
    private double ht = 45;
    private double hr = 1;
    private double[][] value;

    public NeYavnaya() {
        solved();
    }

    public static Method getInstance() {
        if (obj == null) {
            obj = new NeYavnaya();
        }
        return obj;
    }

    private void solved() {
        value = new double[K + 1][I + 1];
        for (int i = 0; i <= I; i++) {
            value[0][i] = Constants.getU0();
        }
        double[][] matA = new double[I + 1][I + 1];
        double[] matB = new double[I + 1];

        for (int k = 1; k <= K; k++) {
            matA[0][0] = getY2();
            matA[0][1] = 4*getY0();
            matB[0]=getY1()*value[k-1][0]+getIY0(0);
            for (int i = 1; i < I; i++) {
                matA[i][i-1]=getY0();
                matA[i][i]=getIY2(i);
                matA[i][i+1]=getIY1(i);
                matB[i]=getY1()*value[k-1][i]+getIY0(i);
            }
            matA[I][I - 1] = getIY1(I)+getY0();
            matA[I][I] = getIY2(I);
            matB[I] = getY1()*value[k-1][I]+getIY0(I);
            double[] matX = propaceMothod(matA, matB);
            for (int i = 0; i <= I; i++) {
                value[k][i]=matX[i];
            }
        }
    }

    @Override
    public double getValueAt(int k, int i) {
        //System.out.println(value[k][i]);
        return value[k][i];
    }

    @Override
    public void setK(int k) {
        this.K = k;
        this.ht = Constants.getTimeEnd() / k;
        solved();
    }

    @Override
    public int getK() {
        return K;
    }

    @Override
    public void setI(int i) {
        this.I = i;
        this.hr = Constants.getRadius() / i;
        solved();
    }

    @Override
    public int getI() {
        return I;
    }

    @Override
    public double getRi(int i) {
        return i * hr;
    }

    @Override
    public double getTk(int k) {
        return k * ht;
    }

    private double[] propaceMothod(double a[][], double[] b) {
        int N = a.length;
        double m;
        for (int i = 1; i < N; i++) {
            m = a[i][i - 1] / a[i - 1][i - 1];

            a[i][i - 1] = 0;
            a[i][i] = a[i][i] - m * a[i - 1][i];
            if (i != N - 1) {
                a[i][i + 1] = a[i][i + 1] - m * a[i - 1][i + 1];
            }
            b[i] = b[i] - m * b[i - 1];
        }
        double[] x = new double[N];
        for (int i = N - 1; i >= 0; i--) {
            if (i == N - 1) {
                x[i] = b[i] / a[i][i];
            } else {
                x[i] = (b[i] - a[i][i + 1] * x[i + 1]) / a[i][i];
            }
        }
        return x;
    }

    private double getY0() {
        return (-Constants.getK())/(Constants.getC()*hr*hr);
    }
    private double getY1() {
        return 1/ht;
    }
    private double getY2() {
        return getY1()+(-4)*getY0()+(2*Constants.getK()*Constants.getAlpha())/(Constants.getC()*Constants.getL());
    }
    
    private double getIY0(int i) {
        double temp1=2*Constants.getK()*Constants.getAlpha()*Constants.getU0();
        double temp2=Constants.getC()*Constants.getL();
        double sum1=temp1/temp2;
        double sum2=Constants.getBetta()/Constants.getC();
        sum2=sum2*Constants.getIntensity(getRi(i));
        return sum1+sum2;
    }
    private double getIY1(int i) {
        double temp=Constants.getC()*hr*hr;
        double sum1=(-Constants.getK()/temp);
        temp=hr*Constants.getC()*getRi(i);
        double sum2=Constants.getK()/temp;
        return sum1+sum2;
    }
    private double getIY2(int i) {
        double sum1=1/ht;
        double temp1=2*Constants.getK();
        double temp2=Constants.getC()*hr*hr;
        double sum2=temp1/temp2;
        temp1=Constants.getK();
        temp2=hr*Constants.getC()*getRi(i);
        double sum3=temp1/temp2;
        temp1=2*Constants.getK()*Constants.getAlpha();
        temp2=Constants.getC()*Constants.getL();
        double sum4=temp1/temp2;
        return sum1+sum2-sum3+sum4;
    }
}
